// 文件路径: dbms/execution/plan/PlanNode.java
package com.dbms.execution.plan;

import java.util.ArrayList;
import java.util.List;

/**
 * PlanNode (计划节点) 代表了查询执行计划中的一个操作节点。
 * 它包含了该节点的描述信息、执行性能指标以及其下的子节点列表。
 * 这个数据结构是实现 EXPLAIN ANALYZE 功能的核心，用于构建和展示查询计划树。
 */
public class PlanNode {

    /**
     * 节点的类型，例如 "Sequential Scan", "Index Scan", "Filter", "Hash Join" 等。
     */
    private final String nodeType;
    /**
     * 节点的详细信息，例如 "on table 'users'", "condition: (id > 10)" 等。
     */
    private final String details;
    /**
     * 该节点的子节点列表。
     */
    private final List<PlanNode> children;

    // --- 性能指标 ---
    /**
     * 【修改】执行耗时，从 Duration 类型改为 long 类型，用于存储更精确的纳秒值。
     */
    private long executionTimeNanos = 0;
    /**
     * 该节点产出（向上层节点传递）的元组数量。
     */
    private long rowsProduced = 0;

    public PlanNode(String nodeType, String details) {
        this.nodeType = nodeType;
        this.details = details;
        this.children = new ArrayList<>();
    }

    /**
     * 向当前节点添加一个子节点。
     * @param child 要添加的子计划节点。
     */
    public void addChild(PlanNode child) {
        // 为安全起见，增加一个 null 检查，避免将 null 子节点添加到列表中。
        if (child != null) {
            this.children.add(child);
        }
    }

    /**
     * 【修改】设置节点的执行时间（以纳秒为单位）。
     * @param executionTimeNanos 耗时纳秒数。
     */
    public void setExecutionTimeNanos(long executionTimeNanos) {
        this.executionTimeNanos = executionTimeNanos;
    }

    /**
     * 设置节点产出的行数。
     * @param rowsProduced 产出的行数。
     */
    public void setRowsProduced(long rowsProduced) {
        this.rowsProduced = rowsProduced;
    }

    /**
     * 将整个计划树格式化为一个易于阅读的字符串。
     * @return 格式化后的字符串。
     */
    public String toFormattedString() {
        StringBuilder sb = new StringBuilder();
        // 从根节点开始，递归地格式化整个树
        formatNode(this, "", true, sb);
        return sb.toString();
    }

    /**
     * 递归地格式化单个节点及其子节点。
     * @param node 当前要格式化的节点
     * @param prefix 用于缩进的字符串前缀
     * @param isTail 标记当前节点是否是其父节点的最后一个子节点（用于绘制树形结构）
     * @param sb 用于构建最终字符串的 StringBuilder
     */
    private void formatNode(PlanNode node, String prefix, boolean isTail, StringBuilder sb) {
        // 打印节点的前缀和类型
        sb.append(prefix).append(isTail ? "-> " : "|-> ");
        sb.append(node.nodeType);
        // 如果有详细信息，则打印
        if (node.details != null && !node.details.isEmpty()) {
            sb.append(" (").append(node.details).append(")");
        }
        // 【修改】打印性能指标。将纳秒转换为毫秒进行显示，以提高可读性。
        sb.append(" (actual time=").append(node.executionTimeNanos / 1_000_000.0).append("ms, rows=").append(node.rowsProduced).append(")\n");

        // 准备下一层子节点的前缀
        String childPrefix = prefix + (isTail ? "    " : "|   ");
        // 递归地格式化所有子节点
        for (int i = 0; i < node.children.size() - 1; i++) {
            formatNode(node.children.get(i), childPrefix, false, sb);
        }
        if (!node.children.isEmpty()) {
            formatNode(node.children.get(node.children.size() - 1), childPrefix, true, sb);
        }
    }
}